using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using TechEd.Data.Core;
using TechEd.Data.Core.Entity.Attribute;
using TechEd.Data.Core.Entity.Base;
using TechEd.RestService.DataLayer.Communication.Exception;

namespace TechEd.RestService.DataLayer.Communication.Base
{
	public abstract class EntityContext<T> : TableServiceContext where T : BaseEntity
	{
		#region static init

		private static readonly string _tableBaseUri = ConfigurationManager.AppSettings["TableStorageEndpoint"];
		private static readonly string _accountName = ConfigurationManager.AppSettings["AccountName"];
		private static readonly string _accountKey = ConfigurationManager.AppSettings["AccountSharedKey"];

		private static readonly string _dataConnectionStringName = ConfigurationManager.AppSettings["DataConnectionStringName"];

		protected static StorageCredentialsAccountAndKey AccountCredentials = new StorageCredentialsAccountAndKey(_accountName, _accountKey);


		static EntityContext()
		{
			CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)));
		}

		protected static CloudStorageAccount StorageAccount { get { return CloudStorageAccount.FromConfigurationSetting(_dataConnectionStringName); } }

		protected static CloudBlobContainer GetBlobContainer(string prefix, string containerName)
		{
			string containerAddress = (prefix + containerName).ToLower();

			CloudBlobClient client = StorageAccount.CreateCloudBlobClient();
			CloudBlobContainer container = client.GetContainerReference(containerAddress);
			container.CreateIfNotExist();
			return container;

		}

		protected static void CheckDatabaseTable(string tableName)
		{
			CloudTableClient tableClient = StorageAccount.CreateCloudTableClient();
			tableClient.CreateTableIfNotExist(tableName);
		}

		protected string SaveFileToBlob(byte[] bytes, MetaPair[] metadata)
		{
			var fileName = metadata.Where(x => x.Name == MetaPair.FileName).Single().Value;

			string blobAddressUri = Guid.NewGuid() + "/" + fileName;
			var blob = GetBlobContainer(Prefix, "files").GetBlobReference(blobAddressUri);

			blob.UploadByteArray(bytes);

			foreach (var pair in metadata)
			{
				blob.Metadata[pair.Name] = pair.Value;
			}
			blob.SetMetadata();

			var contentTypeMeta = metadata.Where(x => x.Name == MetaPair.FileContentType).FirstOrDefault();
			if (contentTypeMeta != null)
			{
				blob.Properties.ContentType = contentTypeMeta.Value;
			}
			blob.SetProperties();

			return blobAddressUri;
		}

		#endregion

		protected string TableName;
		protected string PartitionName;

		protected string Prefix { get; set; }

		protected EntityContext(string tablePrefix) : base(_tableBaseUri, AccountCredentials)
		{
			Prefix = string.Format("{0}Galssoft", tablePrefix);

			TableName = Prefix + typeof(T).GetCustomAttributes(typeof(EntityAttribute), false).Cast<EntityAttribute>().Single().TableName;
			if (!Regex.IsMatch(TableName, @"[a-zA-Z0-9]+"))
				throw new ApplicationException("IncorrectPrefix");

			PartitionName = TableName + "Partition";
		}


		protected IQueryable<T> Query
		{
			get
			{
				CheckDatabaseTable(TableName);
				return CreateQuery<T>(TableName);
			}
		}

		public virtual IList<T> GetAll()
		{
			return Query.ToList();
		}

		public virtual void Insert(T entity)
		{
			if (entity.PartitionKey == null && entity.RowKey == null)
			{
				CheckDatabaseTable(TableName);

				entity.PartitionKey = PartitionName;
				entity.RowKey = Guid.NewGuid().ToString();

				try
				{
					AddObject(TableName, entity);
					SaveChanges();
					Detach(entity);
				}
				catch (System.Exception e)
				{
					Console.WriteLine(e);
				}
			}
			else
			{
				throw new NotImplementedException();
			}
		}
	}
}